<template>
  <div v-if="showDrag" class="app__drag" :style="maskStyle" @click="handleMaskClick">
    <div
      ref="dragContent"
      class="app__drag-content"
      :style="{ top: dragPosition.top + 'px', left: dragPosition.left + 'px' }"
      @click.stop
    >
      <!-- Header 区域 -->
      <div class="app__drag-header" :class="titleClass" @mousedown="startDrag">
        <button class="close-btn" @click="close">×</button>
        <slot name="header">
          <span>{{ title }}</span>
        </slot>
      </div>

      <!-- Content 区域 -->
      <div class="app__drag-body">
        <slot></slot>
      </div>

      <!-- Footer 区域 -->
      <div class="app__drag-footer" :class="footerPositionClass">
        <slot name="footer"></slot>
      </div>
    </div>
  </div>
</template>

<script setup>
import { ref, defineProps, defineEmits, computed, onMounted, onUnmounted, nextTick } from 'vue'

// 定义 Props
const props = defineProps({
  maskClosable: {
    type: Boolean,
    default: true // 是否允许点击遮罩关闭弹框
  },
  customStyle: {
    type: Object,
    default: () => ({}) // 自定义遮罩样式
  },
  title: {
    type: String,
    default: '弹框标题' // 默认标题
  },
  titlePosition: {
    type: String,
    default: 'left', // 标题对齐方式：left 或 center
    validator: value => ['left', 'center'].includes(value)
  },
  footerPosition: {
    type: String,
    default: 'right', // Footer 对齐方式：left、center 或 right
    validator: value => ['left', 'center', 'right'].includes(value)
  }
})

// 定义 Emits
const emit = defineEmits(['update:visible', 'open', 'close'])

const showDrag = ref(false)

// 弹框的初始位置
const dragPosition = ref({ top: 100, left: 100 })
// 观察对象
let observer = null
// 拖拽状态
let isDragging = false
let startX = 0
let startY = 0

// 弹框的尺寸
const dragSize = ref({ width: 0, height: 0 }) // 初始尺寸设为 0
// 获取弹框 DOM 元素
const dragContent = ref(null)
// 遮罩样式计算
const maskStyle = computed(() => ({
  backgroundColor: 'rgba(0, 0, 0, 0.3)',
  top: 0,
  zIndex: 9999,
  width: '100vw',
  height: '100vh',
  ...props.customStyle
}))

// 打开弹框
const open = () => {
  showDrag.value = true
  emit('open')
  nextTick(() => {
    if (dragContent.value) {
      const rect = dragContent.value.getBoundingClientRect()
      dragSize.value = { width: rect.width, height: rect.height }
      // 初始化 ResizeObserver
      observer = new ResizeObserver(() => {
        if (dragContent.value) {
          const rect = dragContent.value.getBoundingClientRect()
          dragSize.value = { width: rect.width, height: rect.height }
        }
      })
      observer.observe(dragContent.value)
    }
  })
}

// 关闭弹框
const close = () => {
  showDrag.value = false
  emit('close')
}

// 点击遮罩处理逻辑
const handleMaskClick = () => {
  if (props.maskClosable) {
    close()
  }
}

// 动态计算标题样式
const titleClass = computed(() => ({
  'title-left': props.titlePosition === 'left',
  'title-center': props.titlePosition === 'center'
}))

// 动态计算 Footer 样式
const footerPositionClass = computed(() => ({
  'footer-left': props.footerPosition === 'left',
  'footer-center': props.footerPosition === 'center',
  'footer-right': props.footerPosition === 'right'
}))

// 开始拖拽
function startDrag(event) {
  isDragging = true
  startX = event.clientX - dragPosition.value.left
  startY = event.clientY - dragPosition.value.top

  document.addEventListener('mousemove', onDrag)
  document.addEventListener('mouseup', stopDrag)
}

// 拖拽中
function onDrag(event) {
  if (!isDragging) return

  const newLeft = event.clientX - startX
  const newTop = event.clientY - startY

  // 动态计算最大范围
  const maxLeft = window.innerWidth - dragSize.value.width
  const maxTop = window.innerHeight - dragSize.value.height

  dragPosition.value = {
    left: Math.max(0, Math.min(newLeft, maxLeft)),
    top: Math.max(0, Math.min(newTop, maxTop))
  }
}

// 停止拖拽
function stopDrag() {
  isDragging = false
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
}

// 清理事件监听器
onUnmounted(() => {
  observer?.disconnect()
  document.removeEventListener('mousemove', onDrag)
  document.removeEventListener('mouseup', stopDrag)
})

// 暴露方法给父组件
defineExpose({
  open,
  close
})
</script>

<style scoped>
.app__drag {
  display: flex;
  position: fixed;
  justify-content: center;
  align-items: center;
  top: 0;
  left: 0;
  width: 100vw;
  height: 100vh;
}

.app__drag-content {
  background: #fff;
  width: 700px;
  position: absolute;
  border-radius: 8px;
  box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
  max-width: 80%;
  max-height: 80%;
  overflow: auto;
  display: flex;
  flex-direction: column;
}

/* Header 样式 */
.app__drag-header {
  padding: 16px 20px;
  display: flex;
  align-items: center;
  border-bottom: 1px solid #eaeaea;
  font-size: 16px;
  font-weight: bold;
  color: #333;
  position: relative;
  cursor: move; /* 添加拖拽光标 */
}

.default-header {
  display: flex;
  align-items: center;
  width: 100%;
}

.close-btn {
  position: absolute;
  top: 16px;
  right: 20px;
  background: none;
  border: none;
  font-size: 20px;
  cursor: pointer;
  color: #999;
  transition: color 0.3s;
}

.close-btn:hover {
  color: #333;
}

/* Title 样式 */
.title-left {
  text-align: left;
}
.title-center {
  justify-content: center;
}

/* Body 样式 */
.app__drag-body {
  padding: 20px;
  flex: 1;
  overflow: auto;
}

/* Footer 样式 */
.app__drag-footer {
  padding: 16px 20px;
  border-top: 1px solid #eaeaea;
}

.footer-left {
  text-align: left;
}
.footer-center {
  text-align: center;
}
.footer-right {
  text-align: right;
}
</style>